#include "oj_common/oj_strea_edirection.h"
namespace ojlb {
namespace oj_common {

OjStreaEdirection::OjStreaEdirection(std::string file_path) : file_path_(file_path), save_std_fid_(-1), save_file_fid_(-1) {}

// TODO: 太贪心了, 下面方法可以改为传参的...

// public:
void OjStreaEdirection::setNewStdInFilePid() {
    pid_t save_file_fid = newOpenCleanFile(file_path_); // 打开需要重定向的目标文件

    if (isStreaEdirectionEnble()) { // 之前有做过重定向
        resetStreaEdirection(0); // 那就恢复重定向
    } else { // 之前没有做个重定向
        setStreaEdirection(save_file_fid, 0); // 那就设置重定向
    }

    save_file_fid_ = save_file_fid;
}

void OjStreaEdirection::setNewStdOutFilePid() {
    pid_t save_file_fid = newOpenCleanFile(file_path_); // 打开需要重定向的目标文件

    if (isStreaEdirectionEnble()) { // 之前有做过重定向
        resetStreaEdirection(1); // 那就恢复重定向
    } else { // 之前没有做个重定向
        setStreaEdirection(save_file_fid, 1); // 那就设置重定向
    }

    save_file_fid_ = save_file_fid;
}

void OjStreaEdirection::setNewStdErrFilePid() {
    pid_t save_file_fid = newOpenCleanFile(file_path_); // 打开需要重定向的目标文件

    if (isStreaEdirectionEnble()) { // 之前有做过重定向
        resetStreaEdirection(2); // 那就恢复重定向
    } else { // 之前没有做个重定向
        setStreaEdirection(save_file_fid, 2); // 那就设置重定向
    }

    save_file_fid_ = save_file_fid;
}

void OjStreaEdirection::resetNewStdInFilePid() {
    resetStreaEdirection(0);
}

void OjStreaEdirection::resetNewStdOutFilePid() {
    resetStreaEdirection(1);
}

void OjStreaEdirection::resetNewStdErrFilePid() {
    resetStreaEdirection(2);
}

// private:
int OjStreaEdirection::newOpenCleanFile(const std::string& file_path) {
    umask(0); // 避免受到平台权限掩码影响
    int fid = open(file_path.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0664); // 不存在则创建, 清空, 写入
    if (fid < 0) {
        oj_common::OjLog::error("打开文件异常, 将影响后续的标准流重定向");
        exit(-1); // TODO: 抛出异常
    }
    return fid;
}

bool OjStreaEdirection::isStreaEdirectionEnble() { return ( save_std_fid_ == -1) ? false : true; /* 只要没有保存, 就是没有发生重定向 */ }

void OjStreaEdirection::setStreaEdirection(int save_file_fid, int std) {
    save_std_fid_ = dup(std); // 保存标准流

    if (dup2(save_file_fid, std) < 0) { // 开始重定向
        oj_common::OjLog::error("无法开始标准输入重定向");
        exit(-1); // TODO: 抛出异常
    };
}

void OjStreaEdirection::resetStreaEdirection(int std) {
    if (dup2(save_std_fid_, std) < 0) {
        oj_common::OjLog::error("无法恢复标准输入重定向");
        exit(-1); // TODO: 抛出异常
    };
    close(save_file_fid_); // 关闭原来的文件
    save_std_fid_ = -1;
    save_file_fid_ = -1;
}


} // namespace oj_common end
} // namespace ojlb end